/**
 * 组合式函数, 用于多种登录方式的逻辑复用
*/

import { ref } from 'vue'
import { useStore } from 'vuex'
import md5 from 'js-md5'
import { useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
import { cloneDeep } from 'lodash'
import { EnterpriseRequest } from '@/services/enterprise'
import { throttle, getMenuList, commonValidate, setUcTokenAsCookie, getInitPath } from '@/utils/utils'
import * as Types from '@/store/types'
import * as LoginInfoTypes from '@/store/modules/LoginInfo/types'
import * as AccountTypes from '@/store/modules/Account/types'
import { resetStore } from '@/store'
import { LocalStorageService, SessionStorageService } from '@/utils/storage'
import { Regex } from '@/utils/validator'
import {
  ACCOUNT_TYPE_MAP,
  CERTIFICATION_TYPE_MAP,
  LOGIN_TYPE_MAP,
  LOGIN_METHOD_MAP,
  CLIENT_TYPE_MAP,
  USER_TYPE_MAP,
  PACKAGE_NAME
} from '@/global-config/const'
import { LoginRequest } from '@/services/login'
import { clearCurrentCacheFlag } from '@/utils/count-down'
import { loginSmsCache } from '../config'

// 通用的登录程序
export default function useCommonLogin(ruleForm: any, currentLoginWay: string) {
  // ------------------------ 变量 ------------------------
  const router = useRouter()
  const store = useStore()
  const loading = ref<boolean>(false)
  const ruleFormRef = ref<any>()
  const captchaUrl = ref<string>('')
  const isCaptcha = ref<boolean>(false)
  const isFirstLogin = ref<boolean>(false)
  const smsTimer = ref<any | undefined>()
  const smsCount = ref<number>(0)

  // ------------------------ 方法 ------------------------
  // 提交按钮的触发
  const onSubmit = throttle(async () => {
    const formEl = ruleFormRef.value
    // 1. 一般校验
    if (!formEl) return
    const validateResult = await commonValidate(formEl)
    if (!validateResult) return
    const params = cloneDeep(ruleForm)
    // 通用参数处理
    Object.assign(params, {
      clientType: CLIENT_TYPE_MAP.web,
      userType: USER_TYPE_MAP.outer, // internal:内部用户 outer:外部用户
    })
    // 定制参数处理
    switch (currentLoginWay) {
      case 'sms':
        Object.assign(params, {
          loginType: LOGIN_TYPE_MAP.code,
          accountType: ACCOUNT_TYPE_MAP.phoneCode,
          loginMethod: LOGIN_METHOD_MAP.phone,
          cerificationType: CERTIFICATION_TYPE_MAP.login // 特有的
        })
        break
      case 'account':
        Object.assign(params, {
          loginType: LOGIN_TYPE_MAP.password,
          accountType: ACCOUNT_TYPE_MAP.password,
          loginMethod: LOGIN_METHOD_MAP.account
        })
        break
      case 'ldap':
        Object.assign(params, {
          loginType: LOGIN_TYPE_MAP.ldap,
          accountType: ACCOUNT_TYPE_MAP.password,
          loginMethod: LOGIN_METHOD_MAP.account,
          userType: USER_TYPE_MAP.internal // 这个ldap的需要重写覆盖
        })
        break
      default:
    }
    // 账号登录需要检测当前账号类型，账号登录检测不同类型，特别处理
    if (currentLoginWay === 'account') {
      // 区分手机号
      if (Regex.phone.test(params.account)) {
        params.phone = params.account
        params.loginMethod = LOGIN_METHOD_MAP.phone
        delete params.account
      }
      // 区分email
      if (Regex.email.test(params.account)) {
        params.email = params.account
        params.loginMethod = LOGIN_METHOD_MAP.email
        delete params.account
      }
      // 只有账号登录才有md5加密，ldap目前加密有问题，需要明文
      params.password = md5(params.password)
    }
    // 2. 数据重置
    resetStore()
    // 3. 登录处理程序
    await doLogin(params)
  }, 600)
  // 登录后的处理程序
  const doLogin = async (params: any | undefined) => {
    loading.value = true
    try {
      // 1. 获取用户code
      let flag = await getSmsCode(params)
      // 2. 获取token相关信息
      flag && (flag = await getToken())
      // 3. 获取是否可用
      flag && (flag = await getAvailable())
      // 4. 检测是否是第一次登录
      flag = (flag && await checkFirstLogin())
      // 5. 获取企业列表
      flag && await getEnterprise()
    } finally {
      loading.value = false
    }
    LocalStorageService.get(PACKAGE_NAME) && SessionStorageService.set(`${PACKAGE_NAME}OpenId`, LocalStorageService.get(PACKAGE_NAME).openId)
  }
  // 获取 userCode
  const getSmsCode = async (params: any) => {
    const { code, data } = await LoginRequest.getUserCode(params)
    if (code !== 200) {
      // 图形验证码的重置
      currentLoginWay !== 'sms' && getImgLoginCode()
      return false
    }
    const { userCode, firstLoginFlag } = data
    ruleForm.userCode = userCode
    const loginInfo = cloneDeep(params)
    delete loginInfo.verificationCode
    delete loginInfo.password
    // 同步一份数据
    store.commit(`${LoginInfoTypes.MODULE_NAME}/${LoginInfoTypes.SET_LOGIN_INFO_DATA}`, {
      loginInfo
    })
    isFirstLogin.value = firstLoginFlag
    return true
  }
  // 检查是否是第一次登录
  const checkFirstLogin = async () => {
    // 非第一次登录
    if (!isFirstLogin.value) {
      return true
    }
    // 提示是第一次登录
    ElMessage.success('首次登录成功，请重置密码！')
    // 跳转走
    router.replace('/resetPassword')
    smsClearCountDownCache() // 移除缓存
    return false
  }
  // 获取 token
  const getToken = async () => {
    const { userCode } = ruleForm
    const getTokenRes = await LoginRequest.getToken({ userCode })
    if (getTokenRes.code !== 200) {
      return false
    }
    const { data: { accessToken, openId, openShortId } } = getTokenRes
    store.commit(`${AccountTypes.MODULE_NAME}/${AccountTypes.SET_ACCOUNT_DATA}`, {
      accessToken,
      openId,
      openShortId,
    })
    // cookie上加 accessToken 用于高德的调用 restapi.amap.com
    setUcTokenAsCookie(accessToken)
    return true
  }
  // 获取是否可用
  const getAvailable = async () => {
    const getAvailableRes = await LoginRequest.getAvailable()
    return getAvailableRes.code === 200
  }
  // 获取企业列表
  const getEnterprise = async () => {
    const enterRes = await EnterpriseRequest.getEnterprise()
    if (enterRes.code !== 200) {
      ElMessage.warning(enterRes.message)
      return
    }
    const { data: { enterprises, departmentName, smallTenancyStatus } } = enterRes
    // 存储基础数据
    store.commit(`${AccountTypes.MODULE_NAME}/${AccountTypes.SET_ACCOUNT_DATA}`, {
      smallTenancyStatus,
      userName: departmentName,
    })
    store.commit(`${Types.GLOBAL_DATA}`, {
      enterpriseList: enterprises
    })
    smsClearCountDownCache() // 移除缓存
    if (!enterprises?.length) {
      ElMessage.warning('未查到所属企业')
      return
    }
    // 多企业去选择企业
    if (enterprises.length > 1) {
      // 跳转到选择企业
      router.replace('/enterprise')
      return
    }
    // 单企业 直接跳转并获取左侧菜单权限列表
    const [{ id }] = enterprises
    store.commit(`${AccountTypes.MODULE_NAME}/${AccountTypes.SET_ACCOUNT_DATA}`, {
      enterpriseId: id
    })
    // 获取动态路由菜单并跳转
    const resources = await getMenuList(true, router)
    resources && router.replace(getInitPath(resources))
  }
  // 通用获取图形验证码
  const getImgLoginCode = throttle(async () => {
    const { account } = ruleForm
    const [checkPass, message] = onCheckAccount(null, account)
    if (!checkPass) {
      ElMessage.warning(message)
      return
    }
    const postData = {
      account,
      phone: '',
      email: '',
      accountType: ACCOUNT_TYPE_MAP.password,
      clientType: CLIENT_TYPE_MAP.web,
      loginType: LOGIN_TYPE_MAP.ldap,
      loginMethod: LOGIN_METHOD_MAP.account,
      userType: USER_TYPE_MAP.internal, // internal:内部用户 outer:外部用户
    }
    const params = cloneDeep(postData)
    // 如果是账号登录，需要特别处理参数
    if (currentLoginWay === 'account') {
      // 区分手机号
      if (Regex.phone.test(params.account)) {
        params.phone = params.account
        params.loginMethod = LOGIN_METHOD_MAP.phone
        delete params.account
        delete params.email
      }
      // 区分email
      if (Regex.email.test(params.account)) {
        params.email = params.account
        params.loginMethod = LOGIN_METHOD_MAP.email
        delete params.account
        delete params.phone
      }
    }
    const result = await LoginRequest.getLoginCode(params)
    const { code, data } = result
    if (code !== 200) return
    captchaUrl.value = data.imgCodeBase64
    isCaptcha.value = true
  }, 600)
  // 通用的校验账号的方法
  const onCheckAccount = (rule:any, value:any, callback?:Function) => {
    const isLdap = currentLoginWay === 'ldap'
    const accountText = isLdap ? 'Ldap账号' : '账号'
    let message = `${accountText}不能为空`
    if (!value) {
      callback && callback(message)
      return [false, message]
    }
    let passFlag = false
    // ldap
    if (isLdap) {
      passFlag = Regex.userNameMicro.test(value) // ldap用户名校验
    } else {
      // 非ldap
      passFlag = passFlag || Regex.phone.test(value) // 校验手机号(非ldap)
      passFlag = passFlag || Regex.email.test(value) // 校验邮箱(非ldap)
      passFlag = passFlag || Regex.userNameMicro.test(value) // 校验用户名(非ldap)
    }
    if (!passFlag) {
      message = `请输入正确格式的${accountText}`
      callback && callback(message)
      return [false, message]
    }
    callback && callback()
    return [true]
  }
  // 发短信移除倒计时标记缓存
  const smsClearCountDownCache = async () => {
    // 成功后，sms登录方式下，移除定时器和缓存标识
    if (currentLoginWay === 'sms') {
      clearCurrentCacheFlag(loginSmsCache)
    }
  }
  return {
    store,
    ruleForm,
    ruleFormRef,
    loading,
    captchaUrl,
    isCaptcha,
    smsCount,
    smsTimer,
    // methods
    onSubmit,
    getImgLoginCode
  }
}
